﻿using LightCAD.Core;
using LightCAD.Core.Elements;
using LightCAD.MathLib;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Reflection.Metadata;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using Teigha.DatabaseServices;
using Teigha.Geometry;
using Group = Teigha.DatabaseServices.Group;
using Line2d = LightCAD.MathLib.Line2d;
using Point2d = Teigha.Geometry.Point2d;
using Polyline2d = LightCAD.MathLib.Polyline2d;
using Vector3d = Teigha.Geometry.Vector3d;

namespace LightCAD.ImpExpDwg
{
    public static class ConvertToAutoCAD
    {

        public static Entity? ConvertLcElementToEntity(Database database, LcElement lcElement)
        {
            Entity? entity = null;
            using (var tran = database.TransactionManager.StartTransaction())
            {

                var blockTable = (BlockTable)database.BlockTableId.GetObject(OpenMode.ForWrite);
                var modelSpace = (BlockTableRecord)blockTable[BlockTableRecord.ModelSpace].GetObject(OpenMode.ForWrite);
                var groups = (DBDictionary)database.GroupDictionaryId.GetObject(OpenMode.ForWrite);
                LayerTable acLyrTbl = database.LayerTableId.GetObject( OpenMode.ForRead) as LayerTable;
                if (lcElement is LcLine)
                {
                    entity = ConvertLcLineToLine(lcElement);
                }
                else if (lcElement is LcArc)
                {
                    entity = ConvertLcArcToArc(lcElement);
                }
                else if (lcElement is LcPolyLine)
                {

                    entity = ConvertLcPolylineToPolyline(lcElement); ;
                }
                else if (lcElement is LcEllipse)
                {
                    entity = ConvertLcEllipseToEllipse(lcElement); ;
                }
                else if (lcElement is LcCircle)
                {
                    entity = ConvertLcCircleToCircle(lcElement);
                }
                else if (lcElement is LcGroup)
                {
                    var lcGroup = lcElement as LcGroup;
                    Group group = new Group();
                    ObjectIdCollection objectIdCollection = new ObjectIdCollection();
                    foreach (var groupEle in lcGroup.Elements)
                    {
                        var groupEntity = ConvertToAutoCAD.ConvertLcElementToEntity(database, groupEle);
                        if (groupEntity != null)
                        {
                            System.Drawing.Color color = new System.Drawing.Color();
                            if (lcElement.Color == "ByLayer")
                            {
                                var lcLayer = lcElement.Document.Layers.GetByName(lcElement.Layer);
                                color = System.Drawing.Color.FromArgb((int)lcLayer.Color);

                            }
                            else
                            {
                                color = ColorTranslator.FromHtml(lcElement.Color);
                            }
                            groupEntity.Color = Teigha.Colors.Color.FromColor(color);
                            if (acLyrTbl.Has(lcElement.Layer))
                            {
                                groupEntity.LayerId = acLyrTbl[lcElement.Layer];
                            }
                            groupEntity.Linetype = lcElement.LineType;
                            modelSpace.AppendEntity(groupEntity);
                            objectIdCollection.Add(groupEntity.Id);
                        }
                    }
                    group.Append(objectIdCollection);
                    groups.SetAt(lcGroup.Name, group);
                }
                else if (lcElement is LcBlockRef)
                {
                    LcBlockRef lcBlockRef = (LcBlockRef)lcElement;
                    if (blockTable.Has(lcBlockRef.Name))
                    {
                        BlockReference blockReference = new BlockReference(lcBlockRef.InsertPoint.ToPoint3d(), blockTable[lcBlockRef.Name]);
                        entity = blockReference;
                    }

                }
                else if (lcElement is DirectComponent)
                {
                    DirectComponent directComponent = (DirectComponent)lcElement;
                    Group group = new Group();
                    ObjectIdCollection objectIdCollection = new ObjectIdCollection();
                    foreach (var curve in directComponent.Curves)
                    {
                        switch (curve.Type)
                        {
                            case Curve2dType.Line2d:
                                {
                                    var line = curve as Line2d;
                                    LcLine lcline = new LcLine(line.Start, line.End);
                                    var cadline = ConvertLcLineToLine(lcline);
                                    modelSpace.AppendEntity(cadline);
                                    tran.AddNewlyCreatedDBObject(cadline, true);
                                    objectIdCollection.Add(cadline.Id);
                                    break;
                                }
                            case Curve2dType.Arc2d:
                                {
                                    var arc = curve as Arc2d;
                                    LcArc lcArc = new LcArc(arc.Center, arc.Radius, arc.StartAngle, arc.EndAngle);
                                    var cadArc = ConvertLcArcToArc(lcArc);
                                    modelSpace.AppendEntity(cadArc);
                                    tran.AddNewlyCreatedDBObject(cadArc, true);

                                    objectIdCollection.Add(cadArc.Id);
                                    break;
                                }
                            case Curve2dType.Polyline2d:
                                {
                                    var pline = curve as Polyline2d;
                                    break;
                                }
                            case Curve2dType.Polygon2d:
                                {
                                    var polygon = curve as Polygon2d;
                                    break;
                                }
                            default:
                                break;
                        }
                    }
                    var baseCurve = directComponent.BaseCurve;
                    switch (baseCurve.Type)
                    {
                        case Curve2dType.Line2d:
                            {
                                var line = baseCurve as Line2d;
                                LcLine lcline = new LcLine(line.Start, line.End);
                                var cadline = ConvertLcLineToLine(lcline);
                                modelSpace.AppendEntity(cadline);
                                tran.AddNewlyCreatedDBObject(cadline, true);
                                objectIdCollection.Add(cadline.Id);
                                break;
                            }
                        case Curve2dType.Arc2d:
                            {
                                var arc = baseCurve as Arc2d;
                                LcArc lcArc = new LcArc(arc.Center, arc.Radius, arc.StartAngle, arc.EndAngle);
                                var cadArc = ConvertLcArcToArc(lcArc);
                                modelSpace.AppendEntity(cadArc);
                                tran.AddNewlyCreatedDBObject(cadArc, true);
                                objectIdCollection.Add(cadArc.Id);
                                break;
                            }
                        case Curve2dType.Polyline2d:
                            {
                                var pline = baseCurve as Polyline2d;
                                break;
                            }
                        case Curve2dType.Polygon2d:
                            {
                                var polygon = baseCurve as Polygon2d;
                                break;
                            }
                        default:
                            break;
                    }
                    group.Append(objectIdCollection);
                    groups.SetAt(group.Name, group);
                }
                tran.Commit();
            }

            return entity;
        }


        public static Line ConvertLcLineToLine(LcElement lcElement)
        {
            LcLine lcLine = (LcLine)lcElement;
            Line line = new Line(lcLine.Start.ToPoint3d(), lcLine.End.ToPoint3d());
            return line;
        }
        public static Arc ConvertLcArcToArc(LcElement lcElement)
        {
            LcArc lcArc = (LcArc)lcElement;
            Arc arc = new Arc(lcArc.Center.ToPoint3d(), lcArc.Radius, lcArc.StartAngle, lcArc.EndAngle);
            return arc;
        }
        public static Polyline ConvertLcPolylineToPolyline(LcElement lcElement)
        {
            LcPolyLine lcPolyLine = (LcPolyLine)lcElement;
            Polyline polyline = new Polyline();
            List<Point2d> points = new List<Point2d>();
            foreach (var segment in lcPolyLine.Segments)
            {
                var startPoint = segment.Start.ToPoint2d();
                if (!points.Contains(startPoint))
                {
                    points.Add(startPoint);
                }
                var endPoint = segment.End.ToPoint2d();
                if (!points.Contains(endPoint))
                {
                    points.Add(endPoint);
                }
            }
            for (int i = 0; i < points.Count; i++)
            {
                polyline.AddVertexAt(i, points[i], 0, 0, 0);
            }
            return polyline;
        }
        public static Ellipse ConvertLcEllipseToEllipse(LcElement lcElement)
        {
            LcEllipse lcEllipse = (LcEllipse)lcElement;
            Ellipse ellipse = new Ellipse();
            ellipse.Set(
                lcEllipse.Center.ToPoint3d(),     // Center
                new Vector3d(0, 0, 1),    // Normal
                new Vector3d(lcEllipse.RadiusX, lcEllipse.AxisX.Y, 0),  // Major Axis
                lcEllipse.RadiusY / 1000,                      // Radius radio
                lcEllipse.StartAngle,                        // Start Angle
                lcEllipse.EndAngle               // End Angle
            );

            return ellipse;
        }
        public static Circle ConvertLcCircleToCircle(LcElement lcElement)
        {
            LcCircle lcCircle = (LcCircle)lcElement;

            Circle circle = new Circle();
            circle.Center = lcCircle.Center.ToPoint3d();
            circle.Normal = new Vector3d(0, 0, 1);
            circle.Radius = lcCircle.Radius;
            return circle;
        }



        public static Point3d ToPoint3d(this Vector2 vector2D)
        {
            return new Point3d(vector2D.X, vector2D.Y, 0);
        }
        public static Point2d ToPoint2d(this Vector2 vector2D)
        {
            return new Point2d(vector2D.X, vector2D.Y);
        }
        public static Teigha.Geometry.Vector3d ToVector3d(this Vector2 vector2D)
        {
            return new Teigha.Geometry.Vector3d(vector2D.X, vector2D.Y, 0);
        }
    }
}
